﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Blog.Core.Util
{
    public static class IdentityGenerator
    {
        private static readonly long BaseDateTicks = new DateTime(1900, 1, 1).Ticks;

        public static Guid NewSequentialGuid()
        {
            /*
            byte[] uid = Guid.NewGuid().ToByteArray();
            byte[] binDate = BitConverter.GetBytes(DateTime.UtcNow.Ticks);

            byte[] secuentialGuid = new byte[uid.Length];

            secuentialGuid[0] = uid[0];
            secuentialGuid[1] = uid[1];
            secuentialGuid[2] = uid[2];
            secuentialGuid[3] = uid[3];
            secuentialGuid[4] = uid[4];
            secuentialGuid[5] = uid[5];
            secuentialGuid[6] = uid[6];
            // set the first part of the 8th byte to '1100' so     
            // later we'll be able to validate it was generated by us   

            secuentialGuid[7] = (byte) (0xc0 | (0xf & uid[7]));

            // the last 8 bytes are sequential,    
            // it minimizes index fragmentation   
            // to a degree as long as there are not a large    
            // number of Secuential-Guids generated per millisecond  

            secuentialGuid[9] = binDate[0];
            secuentialGuid[8] = binDate[1];
            secuentialGuid[15] = binDate[2];
            secuentialGuid[14] = binDate[3];
            secuentialGuid[13] = binDate[4];
            secuentialGuid[12] = binDate[5];
            secuentialGuid[11] = binDate[6];
            secuentialGuid[10] = binDate[7];

            return new Guid(secuentialGuid);
            */

            // 这个算法是从 NHibernate guid.comb 主键策略中提取出来的，也许跟上面的也差不多
            // 出处 NHibernate.Id.GuidCombGenerator

            byte[] array = Guid.NewGuid().ToByteArray();
            DateTime utcNow = DateTime.UtcNow;
            TimeSpan timeSpan = new TimeSpan(utcNow.Ticks - BaseDateTicks);
            TimeSpan timeOfDay = utcNow.TimeOfDay;
            byte[] bytes = BitConverter.GetBytes(timeSpan.Days);
            byte[] bytes2 = BitConverter.GetBytes((long)(timeOfDay.TotalMilliseconds / 3.333333));
            Array.Reverse(bytes);
            Array.Reverse(bytes2);
            Array.Copy(bytes, bytes.Length - 2, array, array.Length - 6, 2);
            Array.Copy(bytes2, bytes2.Length - 4, array, array.Length - 4, 4);
            return new Guid(array);
        }

        public static string NewId()
        {
            return NewSequentialGuid().ToString();
        }
    }
}
